using System;
using System.Collections.Generic;
using BSDS.Commands.Commands.Implementation;
using BSDS.Core.Infrastructure.Logging;
using BSDS.Core.Model.Services;
using BSDS.Core.Model.Services.Geocoding;
using BSDS.Core.Model.Services.Jobs;
using BSDS.Core.Model.Services.Uploading;
using BSDS.Core.Model.Conversion;
using BSDS.Core.Data.Local;
using System.IO;

namespace BSDS.Commands.Commands.Creation.Implementation
{
    public class GeocodeCommandCreator : CommandCreatorBase
    {
        private readonly GeocodingService geoService;
        private readonly AccountService accountService;
        private readonly DataRepository dataRepository;
        private readonly JobRepository jobRepository;
        private readonly JobService jobService;
        private readonly UploadService uploadService;
        private readonly Logger logger;

        public GeocodeCommandCreator(GeocodingService geoService, AccountService accountService, DataRepository dataRepository, 
            JobRepository jobRepository, JobService jobService, UploadService uploadService, Logger logger)
        {
            this.geoService = geoService;
            this.accountService = accountService;
            this.dataRepository = dataRepository;
            this.jobRepository = jobRepository;
            this.jobService = jobService;
            this.uploadService = uploadService;
            this.logger = logger;
        }

        protected override bool Supports(Dictionary<string, string> parameters)
        {
            return parameters.Count >= 1 && parameters.ContainsKey("geocode");
        }

        protected GeocodeCommandConfiguration CreateConfiguration(Dictionary<string, string> parameters)
        {
            var inputFilename = parameters["geocode"];
            
            GeocodingMode geocodingMode = GeocodingMode.Empty;
            if (parameters.ContainsKey("mode"))
            {
                switch (parameters["mode"])
                {
                    case "all":
                        geocodingMode = GeocodingMode.All;
                        break;
                    case "empty":
                        geocodingMode = GeocodingMode.Empty;
                        break;
                    case "reverse":
                        geocodingMode = GeocodingMode.Reverse;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException("Unsupported mode type: " + parameters["mode"]);
                }
            }

            var storeInOutputFile = false;
            var outputFilename = string.Empty;

            var outputFormat = DataFormat.OriginalFormat;
            if (parameters.ContainsKey("toPipe"))
            {
                outputFormat = DataFormat.Pipe;
            }

            if (parameters.ContainsKey("toTab"))
            {
                outputFormat = DataFormat.Tab;
            }

            if (parameters.ContainsKey("toXML"))
            {
                outputFormat = DataFormat.Xml;
            }

            if (parameters.ContainsKey("outfile"))
            {
                storeInOutputFile = true;
                outputFilename = parameters["outfile"];
                if (outputFilename == "*")
                {
                    outputFilename = inputFilename + ".geocoded." + outputFormat.Value;
                }
            }

            var portal = false;
            if (parameters.ContainsKey("portal"))
            {
                portal = true;
            }

            var convertMode = FormatConvertMode.DontConvert;
            if (parameters.ContainsKey("inputformat"))
            {
                var convert = parameters["inputformat"];
                switch (convert)
                {
                    case "multimap":
                        convertMode = FormatConvertMode.ConvertFromMultimap;
                        break;
                    case "mappoint":
                        convertMode = FormatConvertMode.ConvertFromMappoint;
                        break;
                    default:
                        throw new ArgumentOutOfRangeException("Unsupported value for optional parameter /inputformat. Must use 'multimap' or 'mappoint'.");
                }
            }

            var mergeConfigurationFile = string.Empty;
            if (parameters.ContainsKey("mergeconfig"))
            {
                mergeConfigurationFile = parameters["mergeconfig"];
            }

            var deleteConfigurationFile = string.Empty;
            if (parameters.ContainsKey("deleteconfig"))
            {
                deleteConfigurationFile = parameters["deleteconfig"];
            }

            var insertConfigurationFile = string.Empty;
            if (parameters.ContainsKey("insertconfig"))
            {
                insertConfigurationFile = parameters["insertconfig"];
            }

            var resumeCompletedJob = false;
            var completedJobId = string.Empty;

            if (parameters.ContainsKey("resumeCompletedJob"))
            {
                resumeCompletedJob = true;
                completedJobId = parameters["resumeCompletedJob"];
            }

            var uploadAfterMerging = false;
            var dataSourceName = Path.GetFileNameWithoutExtension(inputFilename);
            var entityTypeName = string.Empty;
            var queryKey = string.Empty;
            var dropFilenamePrefix = string.Empty;

            entityTypeName = "BSDSEntity";
            if (parameters.ContainsKey("entity"))
            {
                entityTypeName = parameters["entity"];
            }

            if (parameters.ContainsKey("dropFilenamePrefix"))
            {
                dropFilenamePrefix = parameters["dropFilenamePrefix"];
            }

            if (parameters.ContainsKey("upload"))
            {
                uploadAfterMerging = true;

                if (parameters.ContainsKey("name"))
                {
                    dataSourceName = parameters["name"];                    
                }                

                if (!parameters.ContainsKey("entity"))
                {
                    entityTypeName = dataSourceName + "_entity";
                }

                if (parameters.ContainsKey("queryKey"))
                {
                    queryKey = parameters["queryKey"];
                }
            }

            return new GeocodeCommandConfiguration(inputFilename, geocodingMode, storeInOutputFile,
                 outputFilename, portal, convertMode, outputFormat, uploadAfterMerging, dataSourceName, entityTypeName, queryKey,
                 resumeCompletedJob, completedJobId, dropFilenamePrefix, mergeConfigurationFile, deleteConfigurationFile, insertConfigurationFile);
        }

        protected ICommand Create(GeocodeCommandConfiguration configuration)
        {
            return new GeocodeCommand(geoService, accountService, dataRepository, uploadService, jobRepository, 
                jobService, logger, configuration);
        }

        protected override ICommand Create(Dictionary<string, string> parameters)
        {
            var configuration = CreateConfiguration(parameters);

            return Create(configuration);
        }
    }
}